package cn.pugle.ormtest.hibernate;

import cn.pugle.ormtest.BaseDemo;
import cn.pugle.ormtest.hibernate.dto.CustomerDetail;
import cn.pugle.ormtest.hibernate.dto.OrderDetail;
import cn.pugle.ormtest.hibernate.model.CustomerModel3;
import cn.pugle.ormtest.hibernate.model.OrderModel3;
import cn.pugle.ormtest.hibernate.repository.CustomerRepository;
import cn.pugle.ormtest.hibernate.repository.OrderRepository;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import java.util.Date;
import java.util.List;

import static cn.pugle.ormtest.common.JSON.SNAKE_MAPPER;

/**
 * @author tzp
 * @date 2017/12/25
 */
@Service
public class JpaHibernateDemo implements BaseDemo {

    @Autowired
    private CustomerRepository customerRepository;
    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private EntityManagerFactory entityManagerFactory;
    @Autowired
    private EntityManager entityManager;

    @Override
    @Transactional
    public void create() {
        CustomerModel3 customer = new CustomerModel3();
        customer.setId(1L);
        customer.setName("xxxx");
        customerRepository.save(customer);

        OrderModel3 order = new OrderModel3();
        order.setId(1L);//有id视为update, 但是要先select一下. 发现库里没有, 就做了insert, 但insert的时候不用这个1L.
        order.setOrderDate(new Date());
        order.setPrice(121L);
        order.setAddress("aaaaa");

//comment-switch-relation-1
//        order.setCustomerId(2L);

//comment-switch-relation-2
        //model写了relation, 这里得曲线一下或者: https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#pc-get-reference
        CustomerModel3 tmpCustomer = new CustomerModel3();
        tmpCustomer.setId(1L);//这里还喜加一select一下. 而且对应的customer必须存在. 10000怎么都存不进去

        order.setCustomer(tmpCustomer);
        orderRepository.save(order);//一共3条sql
    }

    @Override
    @Transactional
    public void retrieve() throws JsonProcessingException {
        //by id
        CustomerModel3 customer = customerRepository.findById(1L).get();
        System.out.println(SNAKE_MAPPER.writeValueAsString(customer));

        //count
        long count = customerRepository.count();
        System.out.println("count: " + count);

        //like
        List<CustomerModel3> xxxx = customerRepository.findByNameLike("%xx%");
        System.out.println("like: " + SNAKE_MAPPER.writeValueAsString(xxxx));

        //spring-jpa的create query功能自动实现这个查询
        List<OrderModel3> ordersByCustomer = orderRepository.findByCustomerId(1L);
        System.out.println("findByFK: " + SNAKE_MAPPER.writeValueAsString(ordersByCustomer));

        //-- query by example
//        List<OrderModel3> orders = orderRepository.findAll(Example.of(new OrderModel3()));
        //-- query by criteria
        //-- by specification
        //-- by queryDsl
    }

    @Override
    @Transactional
    public void update() {
        OrderModel3 order = orderRepository.getOne(1L);
        order.setPrice(123L);
        orderRepository.saveAndFlush(order);
    }

    @Override
    @Transactional
    public void delete() {
        orderRepository.deleteById(8L);
        orderRepository.flush();

        orderRepository.deleteById(9L);//删不存在的报错?
        orderRepository.flush();
//        throw new RuntimeException("xx");//测试事务回滚
    }

    @Override
    public void join() throws Exception {
        //comment-switch-relation-1
//        List<OrderModel3> orders = orderRepository.findByCustomerId(1L);
//        System.out.println("orders: " + SNAKE_MAPPER.writeValueAsString(orders));


//comment-switch-relation-2
        CustomerModel3 customer = customerRepository.findById(1L).get();
        System.out.println(SNAKE_MAPPER.writeValueAsString(customer));

        OrderModel3 order = orderRepository.findById(1L).get();
        CustomerModel3 orderCustomer = order.getCustomer();
        System.out.println("manytoone: " + SNAKE_MAPPER.writeValueAsString(orderCustomer));

        List<OrderModel3> customerOrders = customer.getOrders();
        System.out.println("onetomany: " + SNAKE_MAPPER.writeValueAsString(customerOrders));

        //手动join 另见rawSQL
        List<CustomerDetail> customerDetails = customerRepository.customerDetail();
        System.out.println("dto: " + SNAKE_MAPPER.writeValueAsString(customerDetails));

    }

    /**
     * 自己写sql or hql/jpql
     * hql是jpql的超集
     * <p>
     * 好像也支持用xml写?: xx.xml files and be used as a named query
     */
    @Override
    @Transactional
    public void rawSQL() throws Exception {
        //hql to dto
        List<CustomerDetail> customerDetails = customerRepository.customerDetail();
        System.out.println("hql2query: " + SNAKE_MAPPER.writeValueAsString(customerDetails));

        //sql to list<Object> / sql to List<Entity>  / sql arr[a][2]
        List<OrderModel3> orderModel3s = orderRepository.recentOrders();
        System.out.println("sql2entity: " + SNAKE_MAPPER.writeValueAsString(orderModel3s));

        //sql to dto. many-to-one
        List<OrderDetail> orderDetails = orderRepository.recentOrderDetails();
        System.out.println("sql2dto: " + SNAKE_MAPPER.writeValueAsString(orderDetails));
    }

    @Override
    public void page() throws Exception {
        //page
        Page<CustomerModel3> page = customerRepository.findAll(
                new PageRequest(0, 20, Sort.Direction.DESC, "id"));
        System.out.println("page: " + SNAKE_MAPPER.writeValueAsString(page));
    }

    @Override
    public void lazy() throws Exception {
        //或许projection就应该用dto
        //hibernate文档有一章叫fetching
    }
}
